Public: Concord Software Projects : Data Filters
This page last changed on Aug 10, 2007 by imoncada.
The basic concept is that a data filter is capable of taking a set of data, process this data and output something else. A Data Filter is an entity that takes a DataStore (inputDS) and returns another DataStore (outputDS). The only requirement is that the resultant data store has to be "live", meaning that if the values in inputDS change, the same instance of the outputDS once returned by the filter has to change its values accordingly. Also, if the inputDS is changed, the outputDS should change too and it should not be necessary to ask for a new outputDS instance from the filter again. The DataFilter interfaceThe main interfaces used for the data filter framework are currently in the package org.concord.smartgraph in the OTrunkDataUtil project. We should probably move it somewhere else. public void setInputDataStore(DataStore ds); public DataStore getResultDataStore(); which basically set the input data store and retrieve the output data store (very self-explanatory).
public void setFilterDescription(DataFilterDescription desc);
A DataFilterDescription is another interface that allows the configuration of any data filter. The idea is that, on top of some basic properties that all filters should have, it can also store any additional property in the form of name, value. There are default implementations for these two interfaces that make it a lot easier to write filters. Skipping all further explanation, here's an exameple of how to use some of the default filters that are already written. Example No. 1: How to use filtersThis code is taken from the class SimpleExamplePanel in the package org.concord.examples.smartgraph in the Examples project. //Create an initial data store to play around with PointsDataStore originalData = new PointsDataStore(); originalData.addPoint(0, 0); originalData.addPoint(1, 10); originalData.addPoint(2, 5); //Add the initial data store to a table so we can see the values DataTablePanel table1 = new DataTablePanel(); table1.getTableModel().addDataStore(originalData); //Create a "maximum" filter (capable of choosing the maximum y value in the set) DataFilter filter = new DataMaximumFilter(); filter.setFilterDescription(new DefaultDataFilterDescription("maximum")); //Plug in the input data store into the filter filter.setInputDataStore(originalData); //Get the output data store from the filter (which should contain the maximum) DataStore filteredData = filter.getResultDataStore(); //Add the resultant data store to a second table so we can see it DataTablePanel table2 = new DataTablePanel(); table2.getTableModel().addDataStore(filteredData); Now you have two tables (JPanels) that you can display and see how it works. The first table shows the original data and the second table shows the filtered data (the maximum value). You can manually change the values on the first table and see how the second table changes. Notice that when more than one point has the same y value and it's the maximum, the second table will have more than one value. You can run this example here. How to create a new filterInstead of implementing the basic interfaces (which you can also do if you prefer to), there is a more convenient way of writing filters, using the default implementations that are provided in the smartgraph package. The in-place filterOne type of filter that may be easily understood is a filter that works like a "function". It takes a point (x,y) and it returns a new y value for that point. In order to implement filters that will take (x,y) points and return points of the form (x, <something that can be calculated with x and y only>), there is an easy way of doing it. Just extend the InPlaceDataFilter class which has only one abstract function (you are required to implement only one thing). Of course, you can override more mehtods if you need more flexibility or more functionality. Example No. 2: Extending InPlaceDataFilter to write a simple filterLet's write our little "1000x amplifier" example: public class DataAmplifier extends InPlaceDataFilter { public float getYValue(int numSample, float xValue, float inputYValue) { //We don't care about the sample number OR the x value, we just want to amplify the y value by 1000: return inputYValue * 1000; } } That's it! We can now pass a data store through our amplified filter and see those values shoot up! public class DataAmplifier extends InPlaceDataFilter { public final String PROPERTY_MAGNIFICATION = "magnification"; public final int DEFAULT_MAGNIFICATION = 1000; public float getYValue(int numSample, float xValue, float inputYValue) { //We don't care about the sample number OR the x value, we just want to amplify the y value return inputYValue * getMagnificationFactor(); } public float getMagnificationFactor() { try{ DataFilterDescription fDesc = getFilterDescription(); String val = fDesc.getProperty(PROPERTY_MAGNIFICATION); return Float.parseFloat(val); } catch(Exception ex){ //If there is no filter description (null) //OR if the value of the property cannot be parsed into a float, then: return DEFAULT_MAGNIFICATION; } } } The code looks a little more complicated, basically because we are handling the property carefully. //Like example No.1, let's assume we have our initial data store in a variable called originalData //Create the amplifier filter and set it up DataFilter filter = new DataAmplifier(); //We use the DefaultDataFilterDescription for convenience, simply passing a label that identifies the filter. FilterDescription filterDesc = new DefaultDataFilterDescription("amplifier"); filterDesc.setProperty(DataAmplifier.PROPERTY_MAGNIFICATION, "10"); filter.setFilterDescription(filterDesc); //Plug in the input data store into the filter filter.setInputDataStore(originalData); //Get the output data store from the filter (which should now contain the 10x amplified data!) DataStore filteredData = filter.getResultDataStore(); The code above sets up a filter that amplifies the data (y values) by a factor of 10. |
Document generated by Confluence on Jan 27, 2014 16:52 |